/**
 * @author: 團長
 * @date: 2013-9-11-下午5:33:12
 */
package net.loyintean.pearlshell.base.model.impl;

import net.loyintean.pearlshell.base.common.ResultStatusEnum;
import net.loyintean.pearlshell.base.exception.NoDataException;
import net.loyintean.pearlshell.base.model.IResult;

/** 操作结果实现类
 * <p>
 * 2014-3-12 Loy: add two method ( {@link #fail(String)} and
 * {@link #exception(String, Exception)} ) without data. v2.0.0
 * <p>
 * 不允许data和exception为空。适用于即使操作失败或者异常了也需要返回一些数据的情况。<br>
 * 事实上这种情况比较少见。
 * 
 * 
 * @author 團長
 * @since 2014-3-12
 * @version 2.0.0 */
@Deprecated
class ResultImpl<T> implements IResult<T> {

	/** 操作结果数据。
	 * <p>
	 * 注意：这个数据的初始化状态是null。在做getData方法时，一定要进行校验！
	 * 
	 * @author 團長
	 * @since 2013-9-17 */
	private T data = null;

	/** 操作状态
	 * 
	 * @author 團長
	 * @since 2013-9-17 */
	private ResultStatusEnum status = ResultStatusEnum.INIT;

	/** 操作信息
	 * 
	 * @author 團長
	 * @since 2013-9-17 */
	private String message = ResultStatusEnum.INIT.name();

	/** 当状态是EXCEPTION时，可能抛出的异常。
	 * 
	 * @author 團長
	 * @since 2013-9-17 */
	private Exception exception = null;

	/** 创建一个新的实例 ResultImpl。该实例的状态是INIT，message是INIT.name()。data和exception为null。 */
	ResultImpl() {
		super();
	}

	/** 此构造方法只对data做初始化，其它字段的初始化在字段定义的代码行中实现
	 * 
	 * @author 團長
	 * @since 2013-9-18
	 * @param data */
	ResultImpl(T data) {
		this.data = data;
	}

	/** @author 團長
	 * @since 2013-9-18
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#getMessage() */
	@Override
	public final String getMessage() {
		return message;
	}

	/** 只有在 {@link #isException()} 状态下，this.exception才有数据，因此需要封装为一个新的无数据异常。<br>
	 * 其它非 {@link #isSuccess()}状态下，利用message构造新的无数据异常即可。
	 * 
	 * @author 團長
	 * @since 2013-9-18
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#getData()
	 * @throws NoDataException
	 *             如果当前结果的状态不是SUCCESS，将抛出此异常。 */
	@Override
	public T getData() {

		if (isSuccess()) {
			return data;
		} else if (isException()) {
			throw new NoDataException(this.message, this.exception);
		} else {
			throw new NoDataException(this.message);
		}

	}

	/** @author 團長
	 * @since 2013-9-18
	 * @return 如果当前状态是INIT，则返回NoOperateYetException;<br>
	 *         如果是SUCCESS，将返回NoExceptionHappend异常
	 * @see com.sinosig.evaluation.base.model.IResult#getException() */
	@Override
	public final Exception getException() {
		return exception;
	}

	/** 是否操作成功
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#isSuccess() */
	@Override
	public boolean isSuccess() {
		return ResultStatusEnum.SUCCESS.equals(this.status);
	}

	/** 是否刚刚初始化
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#isInit() */
	@Override
	public boolean isInit() {
		return ResultStatusEnum.INIT.equals(this.status);
	}

	/** 是否操作失败
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#isFail() */
	@Override
	public boolean isFail() {
		return ResultStatusEnum.FAIL.equals(this.status);
	}

	/** 是否发生异常
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @return
	 * @see com.sinosig.evaluation.base.model.IResult#isException() */
	@Override
	public boolean isException() {
		return ResultStatusEnum.EXCEPTION.equals(this.status);
	}

	/** 设置入参的执行结果状态为{@link ResultStatusEnum#SUCCESS}，数据为入参data,；message为
	 * {@link ResultStatusEnum#SUCCESS.name()}，不处理exception。
	 * <p>
	 * 入参data不允许为null。否则将抛出异常。
	 * <p>
	 * 如果某个操作确实没有返回任何数据（例如方法返回void），请至少用message作为data。
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @param data
	 *            操作所产生的结果数据。
	 * @throws NoDataException
	 *             如果入参data为null，将抛出此异常。即操作成功时的数据不允许为null。 */
	@Override
	public void success(final T data) throws NoDataException {

		if (data == null) {
			throw new NoDataException("操作成功时的数据不允许为null！");
		}

		changeStatus(data, ResultStatusEnum.SUCCESS.name(), null,
				ResultStatusEnum.SUCCESS);

	}

	/** 设置入参的执行结果状态为{@link ResultStatusEnum#FAIL}
	 * ，数据为入参data，错误信息为message。不处理exception。
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @param data
	 * @param message
	 *            错误提示信息。如果错误信息为null，将使用 {@link ResultStatusEnum#FAIL.name()}
	 *            作为错误信息
	 * @return */
	@Override
	public void fail(final T data, final String message) {

		changeStatus(data, (message == null) ? ResultStatusEnum.FAIL.name()
				: message, null, ResultStatusEnum.FAIL);

	}

	/** 维持原有的data不变。仅仅修改状态、信息和异常数据
	 * 
	 * @author 團長
	 * @since 2014-3-12
	 * @see com.sinosig.evaluation.base.model.IResult#fail(java.lang.String) */
	@Override
	public void fail(String message) {

		changeStatus(null, (message == null) ? ResultStatusEnum.FAIL.name()
				: message, null, ResultStatusEnum.FAIL);

	}

	/** 设置入参的执行结果状态为{@link ResultStatusEnum#EXCEPTION}
	 * ，数据为入参data，错误信息为message，异常为e
	 * 
	 * @author 團長
	 * @since 2013-9-17
	 * @param data
	 * @param message
	 *            错误提示信息。如果错误信息为null，将使用
	 *            {@link ResultStatusEnum#EXCEPTION.name()}作为错误信息
	 * @param e
	 *            当前抛出的异常
	 * @return */
	@Override
	public void exception(final T data, final String message, final Exception e) {

		changeStatus(data, (message == null) ? e.getMessage() : message, e,
				ResultStatusEnum.EXCEPTION);

	}

	/** 维持原有的data不变。仅仅修改状态、信息和异常数据
	 * 
	 * @author 團長
	 * @since 2014-3-12
	 * @see com.sinosig.evaluation.base.model.IResult#exception(java.lang.String,
	 *      java.lang.Exception) */
	@Override
	public void exception(String message, Exception e) {

		changeStatus(null, (message == null) ? e.getMessage() : message, e,
				ResultStatusEnum.EXCEPTION);

	}

	/** 变更当前操作结果的状态。随着状态变更的还有数据（data）、信息（message）和异常（e）。
	 * <p>
	 * 当data为null时，不会覆盖原有的data。
	 * 
	 * @param data
	 *            操作产生的数据。
	 * @param message
	 *            关于操作的提示信息。
	 * @param e
	 *            操作中产生的异常。
	 * @param status
	 *            操作后的状态。 */
	private void changeStatus(final T data, final String message,
			final Exception e, final ResultStatusEnum status) {

		// 当data为null时，要求维持原有数据不变。
		if (data != null) {
			this.data = data;
		}

		this.message = message;
		this.exception = e;
		this.status = status;
	}

	@Override
	public String toString() {
		return "ResultImpl [" + (data != null ? "data=" + data + ", " : "")
				+ (status != null ? "status=" + status + ", " : "")
				+ (message != null ? "message=" + message + ", " : "")
				+ (exception != null ? "exception=" + exception : "") + "]";
	}

}
